package org.example.service;

import com.aliyun.avatar20220130.Client;
import com.aliyun.avatar20220130.models.*;
import com.aliyun.avatar20220130.models.StartInstanceRequest.StartInstanceRequestApp;
import com.aliyun.avatar20220130.models.StartInstanceRequest.StartInstanceRequestUser;
import com.aliyun.avatar20220130.models.StartInstanceResponseBody.StartInstanceResponseBodyData;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;

import jakarta.annotation.PostConstruct;

import org.example.model.AvatarSession;
import org.example.util.RetryUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.function.Predicate;

@Service
public class AvatarService {
    private static final Logger logger = LoggerFactory.getLogger(AvatarService.class);
    private Client client;

    @Value("${aliyun.avatar.access-key-id}")
    private String accessKeyId;

    @Value("${aliyun.avatar.access-key-secret}")
    private String accessKeySecret;

    @Value("${aliyun.avatar.tenant-id}")
    private Long tenantId;

    @Value("${aliyun.avatar.app-id}")
    private String appId;

    @Value("${aliyun.avatar.timeout:30000}")
    private long timeout; // 默认超时时间30秒

    // 线程池用于异步操作
    private ExecutorService executorService;

    @PostConstruct
    public void init() throws Exception {
        logger.info("初始化阿里云数字人服务...");

        // 初始化线程池
        executorService = new ThreadPoolExecutor(
                2, 5, 60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100),
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 初始化阿里云客户端
        Config config = new Config()
                .setAccessKeyId(accessKeyId)
                .setAccessKeySecret(accessKeySecret);

        // 访问的域名
        config.endpoint = "avatar.cn-zhangjiakou.aliyuncs.com";
        client = new Client(config);

        logger.info("阿里云数字人服务初始化完成");
    }

    /**
     * 启动数字人实例
     * 
     * @return 会话信息，包含sessionId和channel
     */
    public AvatarSession startInstance() throws Exception {
        logger.info("开始启动数字人实例...");

        StartInstanceRequestUser user = new StartInstanceRequestUser();
        user.setUserId("user_" + UUID.randomUUID().toString().substring(0, 8));
        user.setUserName("AI助手用户");

        StartInstanceRequestApp app = new StartInstanceRequestApp();
        app.setAppId(appId);

        StartInstanceRequest request = new StartInstanceRequest();
        request.setTenantId(tenantId);
        request.setApp(app);
        request.setUser(user);

        // 设置超时选项
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = Long.valueOf(timeout).intValue();
        runtime.connectTimeout = Long.valueOf(timeout).intValue();

        Future<StartInstanceResponse> future = executorService
                .submit(() -> client.startInstanceWithOptions(request, runtime));

        try {
            StartInstanceResponse response = future.get(timeout, TimeUnit.MILLISECONDS);
            StartInstanceResponseBody responseBody = response.getBody();

            if (null != responseBody.getSuccess() && responseBody.getSuccess()) {
                // 调用成功
                StartInstanceResponseBodyData data = responseBody.getData();
                logger.info("启动数字人实例成功，sessionId: {}", data.getSessionId());

                // 创建并返回会话
                AvatarSession session = new AvatarSession();
                session.setSessionId(data.getSessionId());
                session.setChannel(data.getChannel());
                session.setStartTime(System.currentTimeMillis());
                return session;
            } else {
                // 调用失败
                logger.error("启动数字人实例失败，原因: {}:{}",
                        responseBody.getCode(), responseBody.getMessage());
                throw new Exception("启动数字人实例失败: " + responseBody.getMessage());
            }
        } catch (TimeoutException e) {
            logger.error("启动数字人实例超时", e);
            throw new Exception("启动数字人实例超时，请稍后重试", e);
        } catch (Exception e) {
            logger.error("启动数字人实例异常", e);
            throw e;
        }
    }

    /**
     * 发送文本消息（带重试）
     */
    public void sendText(String sessionId, String text, boolean interrupt) throws Exception {
        // 定义可重试的超时条件
        Predicate<Exception> isRetryable = RetryUtils::isTimeoutException;

        RetryUtils.executeWithRetry(() -> {
            SendTextRequest request = new SendTextRequest();
            request.setTenantId(tenantId);
            request.setSessionId(sessionId);
            request.setInterrupt(interrupt);
            request.setText(text);
            request.setUniqueCode(UUID.randomUUID().toString());

            RuntimeOptions runtime = new RuntimeOptions();
            runtime.readTimeout = Long.valueOf(timeout).intValue();
            runtime.connectTimeout = Long.valueOf(timeout).intValue();

            SendTextResponse response = client.sendTextWithOptions(request, runtime);
            SendTextResponseBody responseBody = response.getBody();

            if (null == responseBody.getSuccess() || !responseBody.getSuccess()) {
                throw new Exception("发送文本消息失败: " + responseBody.getMessage());
            }

            logger.info("发送文本消息成功，uniqueCode: {}", request.getUniqueCode());
            return null;
        }, 1, isRetryable, 1000);
    }

    /**
     * 发送指令消息
     */
    public void sendCommand(String sessionId, String code, Map<String, Object> content) throws Exception {
        logger.info("发送指令消息, sessionId: {}, code: {}", sessionId, code);

        SendCommandRequest request = new SendCommandRequest();
        request.setTenantId(tenantId);
        request.setSessionId(sessionId);
        request.setCode(code);
        request.setContent(content);
        request.setUniqueCode(UUID.randomUUID().toString());

        // 设置超时选项
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = Long.valueOf(timeout).intValue();
        ;
        runtime.connectTimeout = Long.valueOf(timeout).intValue();
        ;

        Future<SendCommandResponse> future = executorService
                .submit(() -> client.sendCommandWithOptions(request, runtime));

        try {
            SendCommandResponse response = future.get(timeout, TimeUnit.MILLISECONDS);
            SendCommandResponseBody responseBody = response.getBody();

            if (null != responseBody.getSuccess() && responseBody.getSuccess()) {
                // 调用成功
                logger.info("发送指令消息成功");
            } else {
                // 调用失败
                logger.error("发送指令消息失败，原因: {}:{}",
                        responseBody.getCode(), responseBody.getMessage());
                throw new Exception("发送指令消息失败: " + responseBody.getMessage());
            }
        } catch (TimeoutException e) {
            logger.error("发送指令消息超时", e);
            throw new Exception("发送指令消息超时，请稍后重试", e);
        } catch (Exception e) {
            logger.error("发送指令消息异常", e);
            throw e;
        }
    }

    /**
     * 停止数字人实例
     */
    public void stopInstance(String sessionId) throws Exception {
        logger.info("停止数字人实例, sessionId: {}", sessionId);

        StopInstanceRequest request = new StopInstanceRequest();
        request.setTenantId(tenantId);
        request.setSessionId(sessionId);

        // 设置超时选项
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = Long.valueOf(timeout).intValue();
        ;
        runtime.connectTimeout = Long.valueOf(timeout).intValue();
        ;

        Future<StopInstanceResponse> future = executorService
                .submit(() -> client.stopInstanceWithOptions(request, runtime));

        try {
            StopInstanceResponse response = future.get(timeout, TimeUnit.MILLISECONDS);
            StopInstanceResponseBody responseBody = response.getBody();

            if (null != responseBody.getSuccess() && responseBody.getSuccess()) {
                // 调用成功
                logger.info("停止数字人实例成功, sessionId: {}",
                        responseBody.getData().getSessionId());
            } else {
                // 调用失败
                logger.error("停止数字人实例失败，原因: {}:{}",
                        responseBody.getCode(), responseBody.getMessage());
                throw new Exception("停止数字人实例失败: " + responseBody.getMessage());
            }
        } catch (TimeoutException e) {
            logger.error("停止数字人实例超时", e);
            throw new Exception("停止数字人实例超时，请稍后重试", e);
        } catch (Exception e) {
            logger.error("停止数字人实例异常", e);
            throw e;
        }
    }

    /**
     * 关闭资源
     */
    public void destroy() {
        if (executorService != null) {
            executorService.shutdown();
        }
    }
}